﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using CYP.IISMonitor.Utility;
using System.Xml;
using CYP.IISMonitor.Utility.SMS;
using CYP.IISMonitor.Utility.Mails;
using CYP.IISMonitor.Utility.Log;

namespace CYP.IISMonitor
{
    partial class IISMonitorService : ServiceBase
    {
        /// <summary>
        /// website xml file
        /// </summary>
        private XmlDocument doc = new XmlDocument();

        /// <summary>
        /// 网站信息文件目录全路径
        /// </summary>
        private string filePath = AppDomain.CurrentDomain.BaseDirectory + "Websites.xml";

        /// <summary>
        /// 日志
        /// </summary>
        private readonly TextLogger _trace = TextLogManager.Create(typeof(IISMonitorService));

        public IISMonitorService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            // TODO: 在此处添加代码以启动服务。
            try
            {
                Excute();

            }
            catch (Exception ex)
            {
                //记录异常日志
                _trace.Error("[Exception]IISMonitorService Start:" + ex.Message);
            }
        }

        /// <summary>
        /// 服务开始执行
        /// </summary>
        public void Excute()
        {
            System.Timers.Timer timer = new System.Timers.Timer();
            timer.Interval = Convert.ToInt64(ConfigHelper.GetConfig("SvcInterval"));
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.Start();
            _trace.Info("IISMonitorService Started!");
        }

        protected override void OnStop()
        {
            // TODO: 在此处添加代码以执行停止服务所需的关闭操作。
            _trace.Info("IISMonitorService Stoped!");
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                Invoke();
            }
            catch (Exception ex)
            {
                //程序异常，记录异常日志
                _trace.Error("[Exception]timer_Elapsed:" + ex.Message);
            }
        }

        /// <summary>
        /// 调用方法
        /// </summary>
        private void Invoke()
        {
            //获取所有站点信息
            doc.Load(filePath);
            XmlNodeList listWebsite = doc.SelectNodes("//Websites//Website");
            foreach (XmlNode item in listWebsite)
            {
                //模拟访问页面，检测IIS是否可用。
                string strAddress = item.Attributes["address"].Value;
                if (String.IsNullOrEmpty(strAddress))
                {
                    throw new Exception(String.Format("{0} Address is Null!", item.Attributes["name"].Value));
                }

                string strIISAddress = strAddress.Split('?')[0];
                string strDataAddress = strAddress;
                bool boIIS = TestIISAdrress(strIISAddress);
                if (!boIIS)
                {
                    RecordError(item, AddressType.IIS);
                }
                else
                {
                    bool boData = TestDataAdrress(strDataAddress);
                    if (!boData)
                    {
                        RecordError(item, AddressType.DATA);
                    }
                }
            }
        }

        /// <summary>
        /// 枚举
        /// </summary>
        private enum AddressType
        {
            IIS,
            DATA
        }

        /// <summary>
        /// 记录访问错误
        /// </summary>
        /// <param name="item"></param>
        /// <param name="type"></param>
        private void RecordError(XmlNode item, AddressType type)
        {
            //发送短信和邮件
            if (Convert.ToBoolean(item.Attributes["notification"].Value))
            {
                int i = UpdateTimesByWebsiteName(item, String.Empty);
                if (i <= Convert.ToInt32(item.Attributes["notificationMax"].Value))
                {
                    string msg = String.Empty;
                    switch (type)
                    {
                        case AddressType.IIS:
                            msg = String.Format("站点[{0}]IIS访问出错。", item.Attributes["name"].Value);
                            break;
                        case AddressType.DATA:
                            msg = String.Format("站点[{0}]数据库访问出错。", item.Attributes["name"].Value);
                            break;
                        default:
                            msg = String.Format("站点[{0}]IIS访问出错。", item.Attributes["name"].Value);
                            break;
                    }

                    if (Convert.ToBoolean(item.Attributes["smsEnable"].Value))
                    {
                        SMSManager.Send(msg);
                    }
                    MailManager.Send(msg);
                    //记录日志文件
                    _trace.Info(msg);
                }
            }
        }

        /// <summary>
        /// 模拟访问页面，检测IIS是否可用。
        /// </summary>
        /// <param name="adrress"></param>
        /// <returns></returns>
        private bool TestIISAdrress(string adrress)
        {
            bool bo = false;
            try
            {
                //实例化模拟客户端请求对象
                System.Net.WebRequest webRequest = System.Net.WebRequest.Create(adrress);
                //得到请求的响应对象
                System.Net.WebResponse webResponse = webRequest.GetResponse();
                bo = true;
            }
            catch (Exception ex)
            {
                //访问失败
                //记录异常日志
                _trace.Error("[Exception]TestIISAdrress:" + ex.Message);
                bo = false;
            }
            return bo;
        }

        /// <summary>
        /// 模拟访问页面，检测数据库可用。
        /// </summary>
        /// <param name="adrress"></param>
        /// <returns></returns>
        private bool TestDataAdrress(string adrress)
        {
            bool bo = false;
            try
            {
                //实例化模拟客户端请求对象
                System.Net.WebRequest webRequest = System.Net.WebRequest.Create(adrress);
                //得到请求的响应对象
                System.Net.WebResponse webResponse = webRequest.GetResponse();

                if (webResponse.Headers.GetValues("result") != null)
                {
                    string[] strResults = webResponse.Headers.GetValues("result");
                    if (strResults.Length > 0)
                    {
                        if (strResults[0].ToLower().Equals("true"))
                        {
                            //数据库可用。
                            bo = true;
                        }
                        else
                        {
                            //数据库不可用
                            bo = false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //访问失败
                //记录异常日志
                bo = false;
            }
            return bo;
        }

        /// <summary>
        /// 更新发送短信的次数
        /// </summary>
        /// <param name="item">某个站点的配置信息节点</param>
        /// <param name="date">日期（发送短信次数根据日期分组）</param>
        /// <returns>返回发送后的次数</returns>
        private int UpdateTimesByWebsiteName(XmlNode item, string date)
        {
            int times = 0;

            if (doc == null)
            {
                throw new Exception("The File Websites.xml Exception!");
            }

            if (String.IsNullOrEmpty(date))
            {
                date = DateTime.Now.ToString("yyyy-MM-dd");
            }


            XmlNode node_SmsEmails = item.SelectSingleNode("SmsEmails");
            if (node_SmsEmails == null)
            {
                #region 判断是否包含SmsEmails节点，不包含则表示第一次发，创建SmsEmails和SmsEmail节点

                node_SmsEmails = doc.CreateElement("SmsEmails");
                XmlNode node_SmsEmails_SmsEmail = doc.CreateElement("SmsEmail");
                XmlAttribute attrTimes = doc.CreateAttribute("times");
                attrTimes.Value = "1";
                XmlAttribute attrDate = doc.CreateAttribute("date");
                attrDate.Value = date;
                node_SmsEmails_SmsEmail.Attributes.Append(attrTimes);
                node_SmsEmails_SmsEmail.Attributes.Append(attrDate);
                node_SmsEmails.AppendChild(node_SmsEmails_SmsEmail);
                item.AppendChild(node_SmsEmails);
                doc.Save(filePath);
                #endregion
            }
            else
            {
                XmlNodeList listSms = item.SelectNodes("SmsEmails//SmsEmail");
                for (int j = 0; j < listSms.Count; j++)
                {
                    if (String.Equals(listSms.Item(j).Attributes["date"].Value, date))
                    {
                        times = Convert.ToInt32(listSms.Item(j).Attributes["times"].Value);
                        if (times > -1 && times < Convert.ToInt32(item.Attributes["notificationMax"].Value))
                        {
                            listSms.Item(j).Attributes["times"].Value = (times + 1).ToString();
                        }
                        //停止内层循环
                        break;
                    }
                    else if (j == listSms.Count - 1)
                    {
                        //最后一次循环，如果未找到当天发送信息记录，则表示当天第一次发送。
                        #region 当天第一次发送信息，创建SmsEmail节点

                        XmlNode node_SmsEmails_SmsEmail = doc.CreateElement("SmsEmail");
                        XmlAttribute attrTimes = doc.CreateAttribute("times");
                        attrTimes.Value = "1";
                        XmlAttribute attrDate = doc.CreateAttribute("date");
                        attrDate.Value = date;
                        node_SmsEmails_SmsEmail.Attributes.Append(attrTimes);
                        node_SmsEmails_SmsEmail.Attributes.Append(attrDate);
                        node_SmsEmails.AppendChild(node_SmsEmails_SmsEmail);
                        doc.Save(filePath);
                        #endregion
                    }
                }
            }

            doc.Save(filePath);
            return times + 1;
        }
    }
}
